#pragma once

enum PARAM_TYPE
{
	PARAM_CHAR,
	PARAM_STRING,
	PARAM_BOOL,
	PARAM_UINT8, PARAM_UINT16, PARAM_UINT32, PARAM_UINT64,
	PARAM_INT8,  PARAM_INT16,  PARAM_INT32,  PARAM_INT64,
	PARAM_FLOAT, PARAM_DOUBLE,
};








#if 0

#include <map>
#include <limits>

namespace paramframe
{

enum ATTR_TYPE
{
	ATTR_TYPE_NULL,
	ATTR_TYPE_OBJECT,
	ATTR_TYPE_CHAR,
	ATTR_TYPE_STRING,
	ATTR_TYPE_BOOL,
	ATTR_TYPE_UINT8,
	ATTR_TYPE_UINT16,
	ATTR_TYPE_UINT32,
	ATTR_TYPE_UINT64,
	ATTR_TYPE_INT8,
	ATTR_TYPE_INT16,
	ATTR_TYPE_INT32,
	ATTR_TYPE_INT64,
	ATTR_TYPE_FLOAT32,
	ATTR_TYPE_FLOAT64,
	ATTR_TYPE_COUNT
};

extern const char * const ATTR_TYPE_NAMES[];

/*
Maps names (or any strings) to unique numbers.
0 is reserved for "invalid/no id" and maps to/from an empty string.
*/
class NameIdManager
{
public:
	NameIdManager();
	~NameIdManager();

	uint NameToId(const char *name);
	uint NameToId(const string &name);
	// Not found: returns empty string.
	const std::string & IdToName(uint id);

private:
	typedef std::map<string, uint> MapType;
	typedef std::map<uint, string> RevMapType;
	MapType m_Map;
	RevMapType m_RevMap;
	uint m_NextId;
};

extern NameIdManager g_NameIdManager;


class Object;
class Context;
class ObjectAttribute;

class Attribute
{
public:
	enum FLAG
	{
		FLAG_INVISIBLE = 0x01,
		FLAG_READ_ONLY = 0x02,
		FLAG_DYNAMIC   = 0x04,
		FLAG_KEY       = 0x08,
		FLAG_AUTO      = 0x10,
	};

	static int NameIdCmp(uint nameId, Attribute *attr) { return UniversalCmp<uint>(nameId, attr->m_NameId); }

	Attribute(const std::string &name, uint minCount, uint maxCount, uint flags);
	virtual ~Attribute() { }

	uint GetValueCount(const Object *obj);
	void SetValueCount(Object *obj, uint newCount);
	void * AccessValue(Object *obj, uint index);
	const void * AccessValue(const Object *obj, uint index);

	uint GetNameId() { return m_NameId; }
	const std::string & GetName();
	int GetOffset() { return m_Offset; }
	uint GetMinCount() { return m_MinCount; }
	uint GetMaxCount() { return m_MaxCount; }
	uint GetFlags() { return m_Flags; }
	uint GetSize();

	virtual ATTR_TYPE GetType() = 0;
	virtual uint GetValueSize() = 0;
	/*virtual void LoadBinary(void *obj, common::Stream &stream, int extraOffset = 0) = 0;
	virtual void SaveBinary(const void *obj, common::Stream &stream, int extraOffset = 0) = 0;
	virtual void LoadText(void *obj, common::Tokenizer &tokenizer, int extraOffset = 0) = 0;
	virtual void SaveText(const void *obj, TokenWriter &tokenizer, int extraOffset = 0) = 0;
	virtual void LoadFromString(void *obj, const std::string &s, int extraOffset = 0);
	virtual void SaveToString(const void *obj, std::string &out, int extraOffset = 0);*/

	void Hash(common::Hash_Calc &calc);
	bool ValidateObject(Object &obj, const char **outErrMsg = NULL);

protected:
	virtual void InitValue(char *ptr) = 0;
	virtual void CopyInitValue(char *newPtr, char *existingPtr) = 0;
	virtual void DeinitValue(char *ptr) = 0;
	virtual bool ValidateValue(char *ptr, const char **outErrMsg) { return true; }
	virtual void ExtraHash(common::Hash_Calc &calc) { }

private:
	uint m_NameId;
	int m_Offset;
	uint m_MinCount, m_MaxCount;
	uint m_Flags;

	friend class Class;
	void InitObject(char *objPtr);
	void FinalizeObject(char *objPtr);
	bool ValidateObject(char *objPtr, const char **outErrMsg);
};

class Class
{
public:
	enum FLAG
	{
		FLAG_ABSTRACT = 0x01,
	};

	static int NameIdCmp(uint nameId, Class *cls) { return UniversalCmp<uint>(nameId, cls->m_NameId); }

	Class(Context &context, const string &name, uint flags);
	~Class();

	uint GetNameId() { return m_NameId; }
	const string & GetName();
	uint GetFlags() { return m_Flags; }
	uint GetSize() { return m_Size; }
	uint GetBaseClassCount() { return m_BaseClasses.size(); }
	Class * const * GetBaseClasses() { return &m_BaseClasses[0]; }
	uint GetAttributeCount() { return m_Attributes.size(); }
	Attribute * GetAttribute(uint index) { return m_Attributes[index]; }
	uint GetObjectCount() { return m_ObjectCount; }

	////// Initialization, stage 1

	void AddBaseClass(Class *c);

	////// Initialization, stage 2

	// Takes ownership, deletes attributes on deletion
	void AddAttribute(Attribute *a);
	
	////// Normal usage

	// Returns true if that's this class or this class inherits from c.
	bool IsClass(Class *c, int *outOffset = NULL);
	Attribute * FindAttributeByName(const string &name);
	uint GetHash();

private:
	enum STATE
	{
		STATE_BASE_CLASSES, // You can add edit classes here
		STATE_ATTRIBUTES, // You can edit attributes here
		STATE_OBJECTS, // You can use objects here
	};

	typedef std::vector<Attribute*> AttrVectorType;

	Context &m_Context;
	STATE m_State;
	uint m_NameId;
	uint m_Flags;
	uint m_Size; // Mutable only in State < STATE_OBJECTS
	std::vector<Class*> m_BaseClasses;
	AttrVectorType m_Attributes; ///< Owner of these objects.
	AttrVectorType m_AttributesByNameId;
	bool m_HashCalculated;
	uint m_Hash;
	uint m_ObjectCount;

	friend class Object;
	void ObjectCtor(Object *obj);
	void ObjectDtor(Object *obj);
	bool IsObjectValid(Object *obj, Attribute **outErrAttr, const char **outErrMsg);

	void Hash();
	void InitObject(char *ptr);
	void FinalizeObject(char *ptr);
	bool ValidateObject(char *ptr, Attribute **outErrAttr, const char **outErrMsg);
};

template <typename T>
class AttributeT : public Attribute
{
public:
	AttributeT(const std::string &name, uint minCount, uint maxCount, uint flags) : Attribute(name, minCount, maxCount, flags) { }
	virtual uint GetValueSize() { return sizeof(T); }
	
	T * AccessValueT(Object *obj, uint index) { return (T*)AccessValue(obj, index); }
	const T * AccessValueT(const Object *obj, uint index) { return (const T*)AccessValue(obj, index); }

	void AddValue(Object *obj, const T &v);
	void InsertValue(Object *obj, const T &v, uint index);
	void RemoveValue(Object *obj, uint index);
	void SwapValues(Object *obj, uint index1, uint index2);
	// Returns index to found value. Not found: returns MAXUINT4.
	uint FindValue(Object *obj, const T &v);

protected:
	virtual void InitValue(char *ptr)
	{
		new (ptr) T(); // Placement new, explicit default constructor call.
	}
	virtual void CopyInitValue(char *newPtr, char *existingPtr)
	{
		new (newPtr) T(*(const T*)existingPtr); // Placement new, copy constructor.
	}
	virtual void DeinitValue(char *ptr)
	{
		((T*)ptr)->~T(); // Explicit destructor call.
	}
};

class Object
{
	friend class Attribute;
	friend class Class;

public:
	Object(Class &cls);
	~Object();

	Class & GetClass() { return m_Class; }
	uint GetSize() { return m_Data.size(); }

	bool IsValid(Attribute **outErrAttr = NULL, const char **outErrMsg = NULL);

private:
	Class & m_Class;
	std::vector<char> m_Data;
};

class Association
{
	friend class Context;

public:
	Association(Context &context, const string &name, Class *cls1, ObjectAttribute *attr1);
	~Association();
	void SetClass2(Class *cls2, ObjectAttribute *attr2);
	void SetClassName2(const string &className2);

	uint GetNameId() { return m_NameId; }
	const std::string & GetName();
	uint GetLinkCount() { return m_LinkCount; }

	bool LinkExists(Object *obj1, Object *obj2);
	// Error: returns false.
	bool TryLinkObjects(Object *obj1, Object *obj2);
	// Error: throws exception.
	void LinkObjects(Object *obj1, Object *obj2);
	// Error: returns false.
	bool TryUnlinkObjects(Object *obj1, Object *obj2);
	// Error: throws exception.
	void UnlinkObjects(Object *obj1, Object *obj2);

private:
	Context &m_Context;
	uint m_NameId;
	Class *m_Classes[2];
	ObjectAttribute *m_Attributes[2];
	uint m_LinkCount;

	////// Used only during initialization
	string m_ClassName2;
};

class Context
{
public:
	// Expects identifier or string
	static void ParseName(std::string &out, common::Tokenizer &tok);

	Context();
	// Automatically destroys owned classes.
	~Context();

	void LoadClasses(common::Stream &s);
	void LinkAssociations();

	uint GetClassCount() { return m_Classes.size(); }
	Class * GetClass(uint index) { return m_Classes[index]; }
	Class * FindClassByName(const string &name);

	uint GetAssociationCount() { return m_Associations.size(); }
	Association * GetAssociation(uint index) { return m_Associations[index]; }
	Association * FindAssociationByName(const string &name);

	uint CalcSumObjectCount();

private:
	typedef std::vector<Class*> ClassVector;
	typedef std::vector<Association*> AssociationVector;
	/// Sorted by NameId
	ClassVector m_Classes;
	AssociationVector m_Associations;
	bool m_InsideDestructor;

	friend class Class;
	void ClassCtor(Class *cls);
	void ClassDtor(Class *cls);

	friend class Association;
	void AssociationCtor(Association *assoc);
	void AssociationDtor(Association *assoc);

	void ParseClass(common::Tokenizer &tok);
	void ParseClassEntry(common::Tokenizer &tok, Class &cls);
	void ParseValueCount(uint &outMinCount, uint &outMaxCount, common::Tokenizer &tok);
	Attribute * CreateAttribute(Class &cls, common::Tokenizer &tok, ATTR_TYPE type, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);
};

class ObjectAttribute : public AttributeT<Object*>
{
	friend class Association;

public:
	static ObjectAttribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);

	ObjectAttribute(const string &name, uint minCount, uint maxCount, uint flags);
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_OBJECT; }
	virtual bool ValidateValue(char *ptr, const char **outErrMsg);

	Association * GetAssociation() { return m_Association; }
	bool LinkExists(Object *thisObj, Object *thatObj);

private:
	Association *m_Association;
};

class CharAttribute : public AttributeT<char>
{
public:
	enum CONSTRAINT
	{
		// 0 = Allow all

		CONSTRAINT_DIGIT        = 0x001, // Include numbers
		CONSTRAINT_HEX_DIGIT    = 0x002, // Include hexadecimal numbers
		CONSTRAINT_ALPHA        = 0x004, // Include alpha chars
		CONSTRAINT_ALPHANUMERIC = 0x008, // Include alphanumeric chars
		CONSTRAINT_WHITE        = 0x010, // Include whitespaces

		CONSTRAINT_NO_ZERO      = 0x020, // Exclude char 0
		CONSTRAINT_NO_EOL       = 0x040, // Exclude end of line
		CONSTRAINT_ANSI_ONLY    = 0x080, // Exclude chars 128..255
		CONSTRAINT_NO_SPECIAL   = 0x100, // Exclude chars 0..31
	};

	static CharAttribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);
	// Constraint parsed: returns a constraint flag, advances tokenizer with Next.
	// Constraint not parsed: returns 0.
	static uint ParseConstraintIdentifier(common::Tokenizer &tok);
	static bool ValidateChar(char ch, uint constraints, const char **outErrMsg = NULL);

	uint Constraints;

	CharAttribute(const string &name, uint minCount, uint maxCount, uint flags);
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_CHAR; }
	virtual bool ValidateValue(char *ptr, const char **outErrMsg);
};

class StringAttribute : public AttributeT<string>
{
public:
	static StringAttribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);

	uint CharConstraints; // Use CharAttribute::CONSTRAINT flags.
	uint MinLength, MaxLength;
	bool IsPassword;

	StringAttribute(const string &name, uint minCount, uint maxCount, uint flags);
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_STRING; }
	virtual bool ValidateValue(char *ptr, const char **outErrMsg);
};

class BoolAttribute : public AttributeT<bool>
{
public:
	static BoolAttribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);

	BoolAttribute(const string &name, uint minCount, uint maxCount, uint flags);
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_BOOL; }
};

template <typename T>
class IntegerAttribute : public AttributeT<T>
{
public:
	enum CONSTRAINT
	{
		CONSTRAINT_NOT_ZERO     = 0x01,
		CONSTRAINT_ODD          = 0x08,
		CONSTRAINT_EVEN         = 0x10,
		CONSTRAINT_POW2         = 0x20,
		CONSTRAINT_POW2_PLUS1   = 0x40,
		CONSTRAINT_POW2_MINUS1  = 0x80,
	};

	template <typename DerivedT>
	static DerivedT * BaseCreate(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);

	T MinValue, MaxValue, Step;
	uint Constraints;

	IntegerAttribute(const string &name, uint minCount, uint maxCount, uint flags);
	virtual bool ValidateValue(char *ptr, const char **outErrMsg);
};

class Uint8Attribute : public IntegerAttribute<uint1> { public:
	static Uint8Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Uint8Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Uint8Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<uint1>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_UINT8; }
};
class Uint16Attribute : public IntegerAttribute<uint2> { public:
	static Uint16Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Uint16Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Uint16Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<uint2>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_UINT16; }
};
class Uint32Attribute : public IntegerAttribute<uint4> { public:
	static Uint32Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Uint32Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Uint32Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<uint4>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_UINT32; }
};
class Uint64Attribute : public IntegerAttribute<uint8> { public:
	static Uint64Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Uint64Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Uint64Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<uint8>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_UINT64; }
};
class Int8Attribute : public IntegerAttribute<int1> { public:
	static Int8Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Int8Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Int8Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<int1>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_INT8; }
};
class Int16Attribute : public IntegerAttribute<int2> { public:
	static Int16Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Int16Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Int16Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<int2>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_INT16; }
};
class Int32Attribute : public IntegerAttribute<int4> { public:
	static Int32Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Int32Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Int32Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<int4>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_INT32; }
};
class Int64Attribute : public IntegerAttribute<int8> { public:
	static Int64Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Int64Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Int64Attribute(const string &name, uint minCount, uint maxCount, uint flags) : IntegerAttribute<int8>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_INT64; }
};


template <typename T>
class RealAttribute : public AttributeT<T>
{
public:
	enum REAL_FLAG
	{
		REAL_FLAG_USE_MIN_VALUE = 0x01,
		REAL_FLAG_USE_MAX_VALUE = 0x02,
		REAL_FLAG_USE_STEP      = 0x04,
		REAL_FLAG_PERCENT       = 0x08,
		REAL_FLAG_ANGLE_RADIANS = 0x10,
		REAL_FLAG_ANGLE_DEGREES = 0x20,
		REAL_FLAG_LOG_SCALE     = 0x40,
	};

	template <typename DerivedT>
	static DerivedT * BaseCreate(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName);

	T MinValue, MaxValue, Step;
	uint Precision; // 0 means not specified.
	uint RealFlags;

	RealAttribute(const string &name, uint minCount, uint maxCount, uint flags);
	virtual bool ValidateValue(char *ptr, const char **outErrMsg);
};

class Float32Attribute : public RealAttribute<float> { public:
	static Float32Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Float32Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Float32Attribute(const string &name, uint minCount, uint maxCount, uint flags) : RealAttribute<float>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_FLOAT32; }
};
class Float64Attribute : public RealAttribute<double> { public:
	static Float64Attribute * Create(Context &ctx, Class &cls, common::Tokenizer &tok, const string &name, uint minCount, uint maxCount, uint flags, const string &typeName) {
		return BaseCreate<Float64Attribute>(ctx, cls, tok, name, minCount, maxCount, flags, typeName);
	}
	Float64Attribute(const string &name, uint minCount, uint maxCount, uint flags) : RealAttribute<double>(name, minCount, maxCount, flags) { }
	virtual ATTR_TYPE GetType() { return ATTR_TYPE_FLOAT64; }
};


#include "ParamFramework.inl"

} // namespace paramframe

#endif // #if 0
